package com.thjk.bdf.common.utils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * 工具类
 */
public class RSAUtil {
	
	private final static Logger logger = LoggerFactory.getLogger(RSAUtil.class);

	/** 指定加密算法为RSA */
	private static final String ALGORITHM = "RSA";
	/** 密钥长度，用来初始化 */
	private static final int KEYSIZE = 1024;
	/** 指定公钥存放文件 */
	//private static String PUBLIC_KEY_FILE = "PublicKey";
	/** 指定私钥存放文件 */
	//private static String PRIVATE_KEY_FILE = "PrivateKey";

	/**
	 * 生成密钥对
	 * 
	 * @throws Exception
	 */
	public static void generateKeyPair(String PUBLIC_KEY_FILE,String PRIVATE_KEY_FILE) throws Exception {

		// /** RSA算法要求有一个可信任的随机数源 */
		// SecureRandom secureRandom = new SecureRandom();

		/** 为RSA算法创建一个KeyPairGenerator对象 */
		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);

		/** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
		// keyPairGenerator.initialize(KEYSIZE, secureRandom);
		keyPairGenerator.initialize(KEYSIZE);

		/** 生成密匙对 */
		KeyPair keyPair = keyPairGenerator.generateKeyPair();

		/** 得到公钥 */
		Key publicKey = keyPair.getPublic();

		/** 得到私钥 */
		Key privateKey = keyPair.getPrivate();

		FileOutputStream oos1 = null;
		FileOutputStream oos2 = null;
		try {
			/** 用对象流将生成的密钥写入文件 */
			oos1 = new FileOutputStream(PUBLIC_KEY_FILE);
			oos2 = new FileOutputStream(PRIVATE_KEY_FILE);
			oos1.write(Base64.getEncoder().encode(publicKey.getEncoded()));
			oos2.write(Base64.getEncoder().encode(privateKey.getEncoded()));
		} catch (Exception e) {
			throw e;
		} finally {
			/** 清空缓存，关闭文件输出流 */
			oos1.close();
			oos2.close();
		}
	}

	/*
	 * 读取秘钥数据
	 */
	public static byte[] readKeyDatas(String keyFilePath) {
		BufferedReader bufferedReader = null;
		try {
			bufferedReader = new BufferedReader(new FileReader(keyFilePath));
			String str = null;
			StringBuilder stringBuilder = new StringBuilder();
			while ((str = bufferedReader.readLine()) != null) {
				if (str.contains("---")) {
					continue;
				}
				stringBuilder.append(str);
			}
			return stringBuilder.toString().getBytes();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				bufferedReader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/*
	 * 生成公钥
	 */
	public static PublicKey getPublicKey(String publicKeyPath) {
		// 1.读取公钥文件,获取公钥数据
		byte[] bytesPublicBase64 = readKeyDatas(publicKeyPath);
		// 2.对读取回来的数据进行Base64解码
		byte[] bytesPublic = Base64.getDecoder().decode(bytesPublicBase64);
		// 3.把解码后的数据,重新封装成一个PublicKey对象
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytesPublic);
		KeyFactory keyFactory = null;
		try {
			keyFactory = KeyFactory.getInstance("RSA");
			PublicKey publicKey = keyFactory.generatePublic(keySpec);
			return publicKey;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}
		return null;
	}

	/*
	 * 生成私钥
	 */
	public static PrivateKey getPrivateKey(String privateKeyPath) {
		// 1.读取私钥文件,获取私钥数据
		byte[] bytesPrivateBase64 = readKeyDatas(privateKeyPath);
		// 2.对读取回来的数据进行Base64解码
		byte[] bytesPrivate = Base64.getDecoder().decode(bytesPrivateBase64);
		// 3.把解码后的数据,重新封装成一个PrivateKey对象
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytesPrivate);
		KeyFactory keyFactory = null;
		try {
			keyFactory = KeyFactory.getInstance("RSA");
			PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
			return privateKey;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}
		return null;
	}

	/*
	 * 加密数据
	 */
	public static String encodeData(PublicKey publicKey, String originData) {
		try {
			Cipher cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] bytesEncrypt = cipher.doFinal(originData.getBytes());
			// Base64编码
			byte[] bytesEncryptBase64 = Base64.getEncoder().encode(bytesEncrypt);
			return new String(bytesEncryptBase64);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		}
		return null;
	}

	/*
	 * 解密数据
	 */
	public static String decodeData(PrivateKey privateKey, String encodeData) {
		try {
			// Base64解码
			byte[] bytesEncrypt = Base64.getDecoder().decode(encodeData);
			// 加密
			Cipher cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] bytesDecrypt = cipher.doFinal(bytesEncrypt);
			return new String(bytesDecrypt);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * MD5加密
	 */
	public static String MD5Hex(String pwd){
		try {
			MessageDigest messageDigest = MessageDigest.getInstance("md5");
			byte[] bytes = pwd.getBytes("utf-8");
			byte[] results = messageDigest.digest(bytes);
			StringBuilder stringBuilder = new StringBuilder();
			for (byte result : results) {
				stringBuilder.append(String.format("%02x", result));
			}
			return stringBuilder.toString();
		} catch (NoSuchAlgorithmException e) {
			logger.info("md5加密异常",e);
		} catch (UnsupportedEncodingException e1) {
			logger.info("md5加密异常",e1);
		}
		return null;
	}
}
